package com.chwl.framework.grpc;

import com.chwl.framework.grpc.service.GrpcRequest;
import com.chwl.framework.grpc.service.GrpcResponse;
import com.chwl.framework.grpc.utils.ProtobufUtils;
import com.chwl.framework.rpc.CommonServiceGrpc;
import com.chwl.framework.rpc.GrpcService;
import com.google.protobuf.ByteString;
import io.grpc.ManagedChannel;
import io.grpc.StatusRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

public class ServerContext {
    Logger logger = LoggerFactory.getLogger(ServerContext.class.getName());
    private ManagedChannel channel;

    private String ip;
    private int port;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    ServerContext(ManagedChannel channel) {
        this.channel = channel;

    }

    public ServerContext(ManagedChannel channel, String ip, int port) {
        this.channel = channel;
        this.ip = ip;
        this.port = port;
    }

    private CommonServiceGrpc.CommonServiceBlockingStub addBlockingStub() {
        if (!channel.isShutdown()) {
            return CommonServiceGrpc.newBlockingStub(channel).withDeadlineAfter(1, TimeUnit.MINUTES);
        }
        return null;
    }

    int MAX_VALUE = 10;

    /**
     * 处理 gRPC 请求
     */
    public GrpcResponse handle(GrpcRequest grpcRequest) throws Exception {
        return handle(grpcRequest, 1);
    }

    /**
     * 处理 gRPC 请求
     */
    public GrpcResponse handle(GrpcRequest grpcRequest, int retryCount) throws Exception {
        CommonServiceGrpc.CommonServiceBlockingStub blockingStub = addBlockingStub();
        try {
            byte[] bytes = ProtobufUtils.serialize(grpcRequest);
            GrpcService.Request request = GrpcService.Request.newBuilder().setRequest(ByteString.copyFrom(bytes)).build();
            ByteString response = blockingStub.handle(request).getReponse();
            return ProtobufUtils.deserialize(response.toByteArray(), GrpcResponse.class);
        } catch (Exception e) {
            if (!(e instanceof StatusRuntimeException) && !e.getMessage().contains("DEADLINE_EXCEEDED")) {
                throw e;
            }
            if (retryCount >= MAX_VALUE) {
                logger.error("server context handle fail,serviceName:{},methodName:{},args:{},error message:{}", grpcRequest.getBeanName(), grpcRequest.getMethodName(), grpcRequest.getArgs(), e.getMessage(), e);
                return null;
            }
            retryCount++;
            return handle(grpcRequest, retryCount);
        }
    }

    /**
     * 获取 Channel
     */
    public ManagedChannel getChannel() {
        return channel;
    }

}
